package com.kunzisoft.switchdatetime.time.widget;
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.kunzisoft.switchdatetime.ResourceTable;
import com.kunzisoft.switchdatetime.date.utils.AttrUtils;
import com.kunzisoft.switchdatetime.date.utils.LogUtil;
import com.kunzisoft.switchdatetime.time.SwitchTimePicker;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;

import java.text.DateFormatSymbols;

/**
 * Draw the two smaller AM and PM circles next to where the larger circle will be.
 */
public class TimeAmPmCirclesView extends Component implements Component.DrawTask {
    private static final String TAG = "AmPmCirclesView";

    // Alpha level of blue color for selected circle.
    private static final float SELECTED_ALPHA = 0.2f;
    // Alpha level of blue color for pressed circle.
    private static final float PRESSED_ALPHA = 0.686f;

    private final Paint mPaint = new Paint();
    private int mBackgroundColor = Color.WHITE.getValue();
    private int mAmPmTextColor = Color.BLACK.getValue();
    private int mSelectBackgroundColor = Color.BLUE.getValue();
    private boolean mInverseSelectedColors = false;
    private float mCircleRadiusMultiplier;
    private float mAmPmCircleRadiusMultiplier;
    private String mAmText;
    private String mPmText;
    private boolean mIsInitialized;

    private static final int AM = SwitchTimePicker.AM;
    private static final int PM = SwitchTimePicker.PM;

    private boolean mDrawValuesReady;
    private int mAmPmCircleRadius;
    private int mAmXCenter;
    private int mPmXCenter;
    private int mAmPmYCenter;
    private int mAmOrPm;
    private int mAmOrPmPressed;

    /**
     * 构造方法
     *
     * @param context context
     */
    public TimeAmPmCirclesView(Context context) {
        this(context, null, 0);
    }

    /**
     * TimeAmPmCirclesView
     *
     * @param context context
     * @param attrs attrs
     */
    public TimeAmPmCirclesView(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * 构造方法
     *
     * @param context context
     * @param attrs attrs
     * @param defStyleAttr defStyleAttr
     */
    public TimeAmPmCirclesView(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        addDrawTask(this::onDraw);
        mIsInitialized = false;

        setCircleColor(AttrUtils.getColorFromAttr(attrs, "timeAmPmBackgroundColor", mBackgroundColor));
        setSelectCircleColor(AttrUtils.getColorFromAttr(attrs, "timeAmPmSelectBackgroundColor", mSelectBackgroundColor));
        setAmPmTextColor(AttrUtils.getColorFromAttr(attrs, "timeAmPmTextColor", mAmPmTextColor));
        setInverseSelectedColors(AttrUtils.getBooleanFromAttr(attrs, "timeAmPmHighlightSelected", mInverseSelectedColors));
    }

    public void initialize(Context context, int amOrPm) {
        if (mIsInitialized) {
            LogUtil.e("AmPmCirclesView may only be initialized once.");
            return;
        }

        String typefaceFamily = context.getString(ResourceTable.String_sans_serif);
        Font.Builder builder = new Font.Builder(typefaceFamily);
        Font font = builder.build();
        mPaint.setFont(font);
        mPaint.setAntiAlias(true);
        mPaint.setTextAlign(TextAlignment.CENTER);

        mCircleRadiusMultiplier =
                Float.parseFloat(context.getString(ResourceTable.Float_circle_radius_multiplier));
        mAmPmCircleRadiusMultiplier =
                Float.parseFloat(context.getString(ResourceTable.Float_ampm_circle_radius_multiplier));
        String[] amPmTexts = new DateFormatSymbols().getAmPmStrings();
        mAmText = amPmTexts[0];
        mPmText = amPmTexts[1];

        setAmOrPm(amOrPm);
        mAmOrPmPressed = -1;

        mIsInitialized = true;
    }

    /**
     * Set to AM or PM mode
     *
     * @param amOrPm AM or PM id
     */
    public void setAmOrPm(int amOrPm) {
        mAmOrPm = amOrPm;
    }

    /**
     * Set to AM or PM mode when pressed
     *
     * @param amOrPmPressed AM or PM pressed
     */
    public void setAmOrPmPressed(int amOrPmPressed) {
        mAmOrPmPressed = amOrPmPressed;
    }

    /**
     * Calculate whether the coordinates are touching the AM or PM circle.
     *
     * @param xCoord xCoord
     * @param yCoord yCoord
     * @return PM or AM
     */
    public int getIsTouchingAmOrPm(float xCoord, float yCoord) {
        if (!mDrawValuesReady) {
            return -1;
        }

        int squaredYDistance = (int) ((yCoord - mAmPmYCenter) * (yCoord - mAmPmYCenter));

        int distanceToAmCenter =
                (int) Math.sqrt((xCoord - mAmXCenter) * (xCoord - mAmXCenter) + squaredYDistance);
        if (distanceToAmCenter <= mAmPmCircleRadius) {
            return AM;
        }

        int distanceToPmCenter =
                (int) Math.sqrt((xCoord - mPmXCenter) * (xCoord - mPmXCenter) + squaredYDistance);
        if (distanceToPmCenter <= mAmPmCircleRadius) {
            return PM;
        }

        // Neither was close enough.
        return -1;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        int viewWidth = getWidth();
        if (viewWidth == 0 || !mIsInitialized) {
            return;
        }

        if (!mDrawValuesReady) {
            int layoutXCenter = getWidth() / 2;
            int layoutYCenter = getHeight() / 2;
            int circleRadius =
                    (int) (Math.min(layoutXCenter, layoutYCenter) * mCircleRadiusMultiplier);
            mAmPmCircleRadius = (int) (circleRadius * mAmPmCircleRadiusMultiplier);
            int textSize = mAmPmCircleRadius * 3 / 4;
            mPaint.setTextSize(textSize);

            // Line up the vertical center of the AM/PM circles with the bottom of the main circle.
            mAmPmYCenter = layoutYCenter - mAmPmCircleRadius / 2 + circleRadius;
            // Line up the horizontal edges of the AM/PM circles with the horizontal edges
            // of the main circle.
            mAmXCenter = layoutXCenter - circleRadius + mAmPmCircleRadius;
            mPmXCenter = layoutXCenter + circleRadius - mAmPmCircleRadius;

            mDrawValuesReady = true;
        }

        // We'll need to draw either a lighter blue (for selection), a darker blue (for touching)
        // or white (for not selected).
        int amColor = mBackgroundColor;
        float amAlpha = 1;
        int pmColor = mBackgroundColor;
        float pmAlpha = 1;

        if (mInverseSelectedColors) {
            if (mAmOrPm == AM) {
                pmColor = mSelectBackgroundColor;
                pmAlpha = SELECTED_ALPHA;
            } else if (mAmOrPm == PM) {
                amColor = mSelectBackgroundColor;
                amAlpha = SELECTED_ALPHA;
            }
            if (mAmOrPmPressed == AM) {
                pmColor = mSelectBackgroundColor;
                pmAlpha = PRESSED_ALPHA;
            } else if (mAmOrPmPressed == PM) {
                amColor = mSelectBackgroundColor;
                amAlpha = PRESSED_ALPHA;
            }
        } else {
            if (mAmOrPm == AM) {
                amColor = mSelectBackgroundColor;
                amAlpha = SELECTED_ALPHA;
            } else if (mAmOrPm == PM) {
                pmColor = mSelectBackgroundColor;
                pmAlpha = SELECTED_ALPHA;
            }
            if (mAmOrPmPressed == AM) {
                amColor = mSelectBackgroundColor;
                amAlpha = PRESSED_ALPHA;
            } else if (mAmOrPmPressed == PM) {
                pmColor = mSelectBackgroundColor;
                pmAlpha = PRESSED_ALPHA;
            }
        }

        // Draw the two circles.
        mPaint.setColor(new Color(amColor));
        mPaint.setAlpha(amAlpha);
        canvas.drawCircle(mAmXCenter, mAmPmYCenter, mAmPmCircleRadius, mPaint);
        mPaint.setColor(new Color(pmColor));
        mPaint.setAlpha(pmAlpha);
        canvas.drawCircle(mPmXCenter, mAmPmYCenter, mAmPmCircleRadius, mPaint);

        // Draw the AM/PM texts on top.
        mPaint.setColor(new Color(mAmPmTextColor));
        int textYCenter = mAmPmYCenter - (int) (mPaint.descent() + mPaint.ascent()) / 2;
        canvas.drawText(mPaint, mAmText, mAmXCenter, textYCenter);
        canvas.drawText(mPaint, mPmText, mPmXCenter, textYCenter);
    }

    /**
     * Get circle background color
     *
     * @return background color
     */
    public int getCircleColor() {
        return mBackgroundColor;
    }

    /**
     * Assign circle background color
     *
     * @param backgroundColor background color
     */
    public void setCircleColor(int backgroundColor) {
        this.mBackgroundColor = backgroundColor;
    }

    /**
     * Get AP/PM text color
     *
     * @return text color
     */
    public int getAmPmTextColor() {
        return mAmPmTextColor;
    }

    /**
     * Assign AP/PM text color
     *
     * @param amPmTextColor text color
     */
    public void setAmPmTextColor(int amPmTextColor) {
        this.mAmPmTextColor = amPmTextColor;
    }

    /**
     * Get select background color
     *
     * @return text color
     */
    public int getSelectCircleColor() {
        return mSelectBackgroundColor;
    }

    /**
     * Set select background color
     *
     * @param selectBackgroundColor background color
     */
    public void setSelectCircleColor(int selectBackgroundColor) {
        this.mSelectBackgroundColor = selectBackgroundColor;
    }

    /**
     * Determine if AM / PM selected and unselected colors must be inverted
     *
     * @param inverseColors true to inverse color
     */
    public void setInverseSelectedColors(boolean inverseColors) {
        this.mInverseSelectedColors = inverseColors;
    }
}